using System;
using System.Diagnostics;
using System.Drawing;
using System.Threading;
using System.Windows.Forms;

namespace Microsoft.WowAddonStudio.Lua.RuntimeService.WowBench
{
	/// <summary>
	/// Represents an OutputControl with RichText handling features.
	/// Implements <see cref="IOutputControl"/>.
	/// </summary>
	public sealed partial class RichTextOutputControl : IOutputControl
	{
		#region Private Variables

		private readonly RichTextBox textBox;
		private readonly object syncRoot = new object();

		#endregion
        
		#region Lifecycle Methods

		/// <summary>
		/// Initializes a new instance of the <see cref="RichTextOutputControl"/> class.
		/// </summary>
		/// <param name="textBox"></param>
		public RichTextOutputControl(RichTextBox textBox)
		{
			if (textBox == null)
				throw new ArgumentNullException("textBox");

			this.textBox = textBox;
			textBox.DetectUrls = false;
			textBox.LinkClicked += OnLinkClicked;
		}

		#endregion

		#region IOutputControl Members

		/// <summary>
		/// Appends text to the current text of a control.
		/// </summary>
		/// <param name="text">The text to append to the current contents of the text box.</param>
		public int AppendText(string text)
		{
			int position = 0;
			MethodInvoker invoker = () =>
			                        	{
											if(linkRegEx.Match(text).Success)
												AppendLink(text );
											else
												textBox.AppendText(text);

											if (textBox.CanFocus) textBox.Focus();
											//HACK: ScrollToCaret has a *bug*.
											textBox.SelectionStart = textBox.Text.Length;
											textBox.SelectionLength = 0;
											textBox.ScrollToCaret();
											textBox.SelectionStart = textBox.Text.Length;
			                        		position = textBox.SelectionStart;
			                        	};
			lock (syncRoot)
			{
				if (textBox.InvokeRequired)
					textBox.Invoke(invoker);
				else
					invoker.Invoke();
			}
			return position;
		}

		/// <summary>
		/// Appends error text to the current text of a control.
		/// </summary>
		/// <param name="text">The text to append to the current contents of the text box.</param>
		public int AppendErrorText(string text)
		{
			int position = 0;
			if (!textBox.IsDisposed)
			{
				MethodInvoker invoker = () =>
				{
					InvokeColorizedText(text, Color.Yellow, Color.Red);
					position = textBox.SelectionStart;
				};
				lock (syncRoot)
				{
					if (textBox.InvokeRequired)
						textBox.Invoke(invoker);
					else
						invoker.Invoke();
				}
			}
			return position;
		}

		/// <summary>
		/// Appends information text to the current text of a control.
		/// </summary>
		/// <param name="text">The text to append to the current contents of the text box.</param>
		public int AppendInfoText(string text)
		{
			int position = 0;
			MethodInvoker invoker = () =>
			{
				InvokeColorizedText(text, Color.LightGreen, Color.Black);
				position = textBox.SelectionStart;
			};
			lock (syncRoot)
			{
				if (textBox.InvokeRequired)
					textBox.Invoke(invoker);
				else
					invoker.Invoke();
			}
			return position;
		}

		/// <summary>
		/// Gets or sets the current text in the text box control.
		/// </summary>
		public string Text
		{
			get { return textBox.Text; }
		}


		/// <summary>
		/// Appends information text with the given colors to the current text of a control.
		/// </summary>
		/// <param name="text">The text to append to the current contents of the text box.</param>
		/// <param name="backColor">The background color of the text.</param>
		/// <param name="foreColor">The fore color of the text.</param>
		private void InvokeColorizedText(string text, Color backColor, Color foreColor)
		{
			textBox.AppendText(Environment.NewLine);
			textBox.AppendText(text);
			if (textBox.CanFocus) textBox.Focus();
			textBox.SelectionStart = textBox.Text.Length;
			textBox.SelectionLength = 0;
			textBox.ScrollToCaret();

			string lastLine = textBox.Lines[textBox.Lines.Length - 1];
			textBox.SelectionStart = textBox.Text.Length - lastLine.Length;
			textBox.SelectionLength = lastLine.Length;
			textBox.SelectionBackColor = backColor;
			textBox.SelectionColor = foreColor;
			textBox.SelectionLength = 0;
			textBox.SelectionStart = textBox.Text.Length;
		}


		/// <summary>
		/// Scrolls the contents of the control to the current caret position.
		/// </summary>
		public void ScrollToCaret()
		{
			MethodInvoker invoker = textBox.ScrollToCaret;
			if (textBox.InvokeRequired)
				textBox.BeginInvoke(invoker);
			else
				invoker.Invoke();
		}

		/// <summary>
		/// Gets or sets the starting point of text selected in the control.
		/// </summary>
		public int Position
		{
			get
			{
                if (!textBox.IsDisposed)
                    return textBox.SelectionStart;
			    return 0;
			}
			set { textBox.SelectionStart = value; }
		}

		#endregion

		#region IDisposable Members


		/// <summary>
		/// Performs application-defined tasks associated with freeing,
		/// releasing, or resetting unmanaged resources.
		/// </summary>
		public void Dispose()
		{
			if(textBox != null)
				textBox.LinkClicked -= OnLinkClicked;

			if(webProcess != null)
			{
				try
				{
					webProcess.Kill();
				}
				catch (Exception e)
				{
					Trace.WriteLine(e);
				}
			}
		}

		#endregion

	}
}